package nl.zoidberg.calculon.engine;

import java.util.List;

import nl.zoidberg.calculon.engine.BitBoard.BitBoardMove;

public abstract class StraightMoveGenerator extends PieceMoveGenerator {

	protected abstract byte getPieceType();
	
	public abstract int[][] getDirections();

	protected void makeUpBoardMoves(BitBoard bitBoard, long source,
			long destinations, int distance, boolean alreadyInCheck, boolean safeFromCheck, List<BitBoardMove> rv) {
		
		byte player = bitBoard.getPlayer();
		int shift = distance;
		boolean isCapture = false;

		while( !isCapture && (destinations>>>shift & source) != 0) {
			long moveTo = source<<shift;
			if((moveTo & bitBoard.getBitmapColor(player)) != 0) {
				return;
			}
			
			isCapture = (moveTo & bitBoard.getBitmapOppColor(player)) != 0; 
			BitBoardMove bbMove;
			if(isCapture) {
				// This is a capturing move.
				bbMove = BitBoard.generateCapture(
						source, moveTo, player, getPieceType(), bitBoard.getPiece(moveTo));
			} else {
				bbMove = BitBoard.generateMove(source, moveTo, player, getPieceType());
			}
			
			if(safeFromCheck) {
				rv.add(bbMove);
			} else {
				bitBoard.makeMove(bbMove);
            	if( ! CheckDetector.isPlayerJustMovedInCheck(bitBoard, ! alreadyInCheck)) {
	                rv.add(bbMove);
            	}
				bitBoard.unmakeMove();
			}
			
			shift += distance;;
		}
	}
	
	protected void makeDownBoardMoves(BitBoard bitBoard, long source,
			long destinations, int distance, boolean alreadyInCheck, boolean safeFromCheck, List<BitBoardMove> rv) {
		
		byte player = bitBoard.getPlayer();
		int shift = distance;
		boolean isCapture = false;
		
		while( !isCapture && (destinations<<shift & source) != 0) {
			long moveTo = source>>>shift;
			if((moveTo & bitBoard.getBitmapColor(player)) != 0) {
				return;
			}
			
			isCapture = (moveTo & bitBoard.getBitmapOppColor(player)) != 0; 
			BitBoardMove bbMove;
			if(isCapture) {
				// This is a capturing move.
				bbMove = BitBoard.generateCapture(
						source, moveTo, player, getPieceType(), bitBoard.getPiece(moveTo));
			} else {
				bbMove = BitBoard.generateMove(source, moveTo, player, getPieceType());
			}
			
			if(safeFromCheck) {
				rv.add(bbMove);
			} else {
				bitBoard.makeMove(bbMove);
            	if( ! CheckDetector.isPlayerJustMovedInCheck(bitBoard, ! alreadyInCheck)) {
	                rv.add(bbMove);
            	}
				bitBoard.unmakeMove();
			}

			shift += distance;;
		}
	}
}
